#define _GNU_SOURCE
#include "app_serial.h"
#include "log/log.h"

/**
 *  初始化
 */
int app_serial_init(Device *device)
{
    app_serial_setBraudRate(device, BR_9600);
    
    app_serial_setParity(device, Parity_None);
    app_serial_setStopBits(device, SB_1);
    app_serial_setRaw(device);

    // 刷新串口属性
    int result = tcflush(device->fd, TCIOFLUSH);
    if(result == -1)
    {
        log_error("串口初始化设置失败");
        return -1;
    }
    log_debug("串口初始化设置成功");
    return 0;
}

/**
 * 设置波特率
 */
int app_serial_setBraudRate(Device *device, BraudRate baud_rate)
{
    struct termios attr ;
    //获取串口属性
    tcgetattr(device->fd, &attr);
    // 修改属性（波特率）
    cfsetspeed(&attr, baud_rate);
    //设置串口属性 TCSAFLUSH 当前不生效，刷新后才生效
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result == -1)
    {
        log_error("设置波特率失败");
        return -1;
    }
    log_debug("设置波特率成功");
    return 0;
}

/**
 * 设置校验位
 */
int app_serial_setParity(Device *device, Parity parity)
{
    struct termios attr ;
    //获取串口属性
    tcgetattr(device->fd, &attr);
    // 修改属性（校验位）
    attr.c_cflag &= ~(PARENB | PARODD); //清除校验位
    attr.c_cflag |= parity; //设置校验位
    //设置串口属性 TCSAFLUSH 当前不生效，刷新后才生效
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result == -1)
    {
        log_error("设置校验位失败");
        return -1;
    }
    log_debug("设置校验位成功");
    return 0;
}

/**
 * 设置停止位
 */
int app_serial_setStopBits(Device *device, StopBits stop_bits)
{
    struct termios attr ;
    //获取串口属性
    tcgetattr(device->fd, &attr);
    // 修改属性（停止位）
    attr.c_cflag &= ~CSTOPB; //清除停止位
    attr.c_cflag |= stop_bits; //设置停止位
    //设置串口属性 TCSAFLUSH 当前不生效，刷新后才生效
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result == -1)
    {
        log_error("设置停止位失败");
        return -1;
    }
    log_debug("设置停止位成功");
    return 0;
}

/**
 * 设置是否阻塞
 */
int app_serial_setBlock(Device *device, int is_block)
{
    struct termios attr ;
    //获取串口属性
    tcgetattr(device->fd, &attr);
    // 修改属性（阻塞模式）
    if (is_block == 1)
    {
        attr.c_cc[VMIN] = 1; // 至少读一个字符
        attr.c_cc[VTIME] = 0; // 没有数据时一直等待
    }
    else
    {
        attr.c_cc[VMIN] = 0; // 读取0个字符
        attr.c_cc[VTIME] = 2; // 等待 2*100ms
    }
    //设置串口属性 TCSAFLUSH 当前不生效，刷新后才生效
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result == -1)
    {
        log_error("设置阻塞模式失败");
        return -1;
    }
    log_debug("设置阻塞模式成功");
    return 0;
}

/**
 * 设置为原始模式
 */
int app_serial_setRaw(Device *device)
{
    struct termios attr ;
    //获取串口属性
    tcgetattr(device->fd, &attr);
    // 修改属性（原始模式）
    cfmakeraw(&attr);
    //设置串口属性 TCSAFLUSH 当前不生效，刷新后才生效
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result == -1)
    {
        log_error("设置原始模式失败");
        return -1;
    }
    log_debug("设置原始模式成功");
    return 0;
}
